import java.awt.Image;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;

import javax.media.opengl.GL;
import javax.media.opengl.glu.GLU;

import com.sun.opengl.util.texture.Texture;
import com.sun.opengl.util.texture.TextureData;
import com.sun.opengl.util.texture.TextureIO;


public class BoatNew {
	GL gl;
	GLU glu;
	int COUNT_DOT=11;
	int ZOOM=1;
	int SIZE=8;
	private int LENGTH_DOT;
	private int HEIGHT_DOT;
	private int WIDTH_DOT;
	private int STOP;
	private float kolx, koly,start_time;

	
	private int shaderprogram;
	private int vert_shader, frag_shader;
	private Vector3D A, B;
	
	Texture boxTexture1;
	private int[] tex=new int[1];
	
    Matrix4x4 maty = new Matrix4x4();
    Matrix4x4 matz = new Matrix4x4();
    Matrix4x4 matx = new Matrix4x4();
	
    Matrix4x4 shiftM = new Matrix4x4();
    Matrix4x4 backM = new Matrix4x4();
    
	Vector3D mass[][];
	
	public BoatNew(GL gl_, GLU glu_, int l, int h, int w){
		gl=gl_;
		glu=glu_;
		LENGTH_DOT=l;
		HEIGHT_DOT=h;
		WIDTH_DOT=w;
		CreateTexture(null);
		loadShader();
		mass=new Vector3D[5][];
		makeMass();
		A=new Vector3D();
		B=new Vector3D();
		start_time = System.currentTimeMillis()%100000;
	}
	
	 private void CreateTexture(Image image)
	 {
		 URL imageURL= this.getClass().getResource(
				 "qwerty.png");
	        
		 TextureData data=null;
		 try {
			 data = TextureIO.newTextureData(
					 imageURL.openStream(),false, "png");
			 boxTexture1 = TextureIO.newTexture(data);
		 } catch (IOException exc) {
			 exc.printStackTrace();
			 System.exit(1);
		 }       
	        
		 gl.glEnable(GL.GL_TEXTURE_2D);
		 
		 gl.glGenTextures(1,tex, 0);
		 gl.glBindTexture(GL.GL_TEXTURE_2D, tex[0]);
		 gl.glTexImage2D(GL.GL_TEXTURE_2D, 0,GL.GL_RGBA,data.getWidth(),data.getHeight(),0,GL.GL_RGBA,
				 GL.GL_UNSIGNED_BYTE,data.getBuffer());
//		 gl.glTexParameteri(GL.GL_TEXTURE_2D,GL.GL_TEXTURE_MAG_FILTER,GL.GL_LINEAR);
//		 gl.glTexParameteri(GL.GL_TEXTURE_2D,GL.GL_TEXTURE_MIN_FILTER,GL.GL_LINEAR);
	 }
	
	private void makeMass(){
		mass[0]=makeCube(2*SIZE, 3*SIZE+2.5f, 3, SIZE, 3, 1, 0);
		mass[1]=makeCube(3*SIZE, 3*SIZE+2.5f, 3, SIZE, 3, 1, 0);
		mass[2]=makeNouse(mass[0]);
		STOP=2;
		mass[3]=makePipe(new Vector3D(
				(mass[0][4].x()+mass[0][5].x())/2,
				(mass[0][4].y()+mass[0][7].y())/2,
				mass[0][4].z()), 5f, 1f);
		mass[4]=makePipe(new Vector3D(
				(mass[1][4].x()+mass[1][5].x())/2,
				(mass[1][4].y()+mass[1][7].y())/2,
				mass[1][4].z()), 5f, 1f);
		kolx=((mass[0][4].x()+mass[0][5].x())/2+
	    		(mass[1][4].x()+mass[1][5].x())/2)/2;
		koly=((mass[0][4].y()+mass[0][7].y())/2+
				(mass[1][4].y()+mass[1][7].y())/2)/2;
		//mass=makeCube(20, 20, 3, 5, 3, 1, 0);
	}
	
	private Vector3D[] makePipe(Vector3D c,
			float h, float r)
	{
		Vector3D[] pipe=new Vector3D[32];
		for(int i=0; i<32; ++i)
			pipe[i]=new Vector3D();
		pipe[0].setXYZ(c.x()+r, c.y(), c.z());
		int k=0;
		for(int i=0; i<32; i+=4)
		{
			pipe[i].setXYZ(c.x()+
					r*(float)Math.cos(k*Math.PI/4),
					c.y()+r*(float)Math.sin(k*Math.PI/4),
					c.z());
			pipe[i+1].setXYZ(pipe[i].x(), pipe[i].y(),
					pipe[i].z()+h);
			pipe[i+2].setXYZ(c.x()+
					r*(float)Math.cos((k+1)*Math.PI/4),
					c.y()+r*(float)Math.sin((k+1)*Math.PI/4),
					pipe[i+1].z());
			pipe[i+3].setXYZ(pipe[i+2].x(), pipe[i+2].y(),
					pipe[i+2].z()-h);
			++k;
		}
		return pipe;
	}
	
	private Vector3D[] makeNouse(Vector3D[] wall)
	{
		Vector3D[] nouse=new Vector3D[16];
		for(int i=0; i<16; ++i)
			nouse[i]=new Vector3D();
		
		Vector3D dot=new Vector3D();
		
		dot.setXYZ((wall[0].x())-3,
				(wall[0].y()+wall[3].y())/2, wall[4].z());
		//dot.setXYZ(wall[0].x()+5, wall[0].y()+5, wall[4].z());
		
		//низ
		nouse[0]=wall[0];
		nouse[1]=dot;
		nouse[2]=dot;
		nouse[3]=wall[3];
		
		//верх
		nouse[4]=wall[4];
		nouse[5]=dot;
		nouse[6]=dot;
		nouse[7]=wall[7];
		
		//передний бок
		nouse[8]=wall[0];
		nouse[9]=dot;
		nouse[10]=dot;
		nouse[11]=wall[4];
		
		//задний бок
		nouse[12]=wall[3];
		nouse[13]=dot;
		nouse[14]=dot;
		nouse[15]=wall[7];
		
		return nouse;
	}
	
	private Vector3D[] makeCube(float x, float y,
			float w, float l, float h,
			int fx, int fy){
		Vector3D[] cube=new Vector3D[24];
		//куб строим так. сначала нижняя, потом верхняя,
		//затем боковые по часовой. начало x y.
		for(int i=0; i<24; ++i)
		{
			cube[i]=new Vector3D();
		}
		//низ
		cube[0].setXYZ(x, y, 0);
		cube[1].setXYZ(x+fx*l+fy*w, y, 0);
		cube[2].setXYZ(cube[1].x(), y+fx*w+fy*l, 0);
		cube[3].setXYZ(cube[2].x()-fx*l-fy*w, cube[2].y(), 0);
		
		//верх
		cube[4].setXYZ(cube[0].x()-ZOOM*fy,
				cube[0].y()-ZOOM*fx, h);
		//cube[4].setZ(h);
		cube[5].setXYZ(cube[1].x()+ZOOM*fy,
				cube[1].y()-ZOOM*fx, h);
		//cube[5].setZ(h);
		cube[6].setXYZ(cube[2].x()+ZOOM*fy,
				cube[2].y()+ZOOM*fx, h);
		//cube[6].setZ(h);
		cube[7].setXYZ(cube[3].x()-ZOOM*fy,
				cube[3].y()+ZOOM*fx, h);
		//cube[7].setZ(h);
		
		//передний бок
		cube[8]=cube[4];
		cube[9]=cube[0];
		cube[10]=cube[1];
		cube[11]=cube[5];
		
		//левый бок
		cube[12]=cube[5];
		cube[13]=cube[1];
		cube[14]=cube[2];
		cube[15]=cube[6];
		
		//задний бок
		cube[16]=cube[6];
		cube[17]=cube[2];
		cube[18]=cube[3];
		cube[19]=cube[7];
		
		//правый бок
		cube[20]=cube[7];
		cube[21]=cube[3];
		cube[22]=cube[0];
		cube[23]=cube[4];
		return cube;
	}
	
	public void draw(Camera player, Vector3D sun){
		gl.glActiveTexture(GL.GL_TEXTURE0);
		//gl.glDisable(GL.GL_TEXTURE_2D);
		gl.glColor3f(0.1f, 0.5f, 0.5f);
		gl.glDisable(GL.GL_CULL_FACE);
		
		gl.glActiveTexture(GL.GL_TEXTURE0);
	    gl.glBindTexture(GL.GL_TEXTURE_2D,tex[0]-1);
	    
	    arbWithMatrix(kolx,
				koly);
	    Vector3D A1=new Vector3D();
	    Vector3D B1=new Vector3D();
	    Vector3D C1=new Vector3D();
	    Vector3D D1=new Vector3D();
	    
		
		gl.glUseProgram(shaderprogram);
		
		gl.glUniform3f(gl.glGetUniformLocation(
		shaderprogram, "lightPos"), sun.x(), sun.y(),
		sun.z());
		
		gl.glUniform1i(gl.glGetUniformLocation(
				shaderprogram, "map"), 0);
		
		gl.glUniform3f(gl.glGetUniformLocation(
		shaderprogram, "eyePos"), player.pos.x()
		, player.pos.y(), player.pos.z());
		
		gl.glBegin(GL.GL_QUADS);
		Vector3D n=new Vector3D();
		
		for(int j=0; j<5; ++j)
		{
			int br=24;
			if(j>=3)
				br=32;
		for(int i=0; i<br; i+=4)
		{
			int k=-1;
			if(i>15 && j<3)
				k=1;
			if(j==STOP)
			{
				k=-1;
				if(i==16)
					break;
			}
			//if(huypizda%1000==0){
			A1=Matrix4x4.mult(shiftM, mass[j][i]);
			B1=Matrix4x4.mult(shiftM, mass[j][i+1]);
			C1=Matrix4x4.mult(shiftM, mass[j][i+2]);
			D1=Matrix4x4.mult(shiftM, mass[j][i+3]);
			//huypizda=0;
			//}
			A1=Matrix4x4.mult(maty, A1);
			B1=Matrix4x4.mult(maty, B1);
			C1=Matrix4x4.mult(maty, C1);
			D1=Matrix4x4.mult(maty, D1);
			
			A1=Matrix4x4.mult(backM, A1);
			B1=Matrix4x4.mult(backM, B1);
			C1=Matrix4x4.mult(backM, C1);
			D1=Matrix4x4.mult(backM, D1);
			
			A.setXYZ(D1.x()-A1.x(),
					D1.y()-A1.y(),
					D1.z()-A1.z());
			B.setXYZ(B1.x()-A1.x(),
					B1.y()-A1.y(),
					B1.z()-A1.z());
			n=getNorm(B, A);
			 
			gl.glNormal3f(k*n.x(), k*n.y(), k*n.z());
			
			gl.glTexCoord2f(0f, 0f);
			
				gl.glVertex3f(A1.x(), 
						 A1.y(), A1.z());
				
				gl.glTexCoord2f(0f, 1f);
				
				 gl.glVertex3f(B1.x(), 
						 B1.y(), B1.z());
				 
				 gl.glTexCoord2f(1f, 1f);
				 
				 gl.glVertex3f(C1.x(), 
						 C1.y(), C1.z());
				 
				 gl.glTexCoord2f(1f, 0f);
				 
				 gl.glVertex3f(D1.x(), 
						 D1.y(), D1.z());			
		}
		}
		gl.glEnd();
		gl.glUseProgram(0);
		gl.glEnable(GL.GL_CULL_FACE);
		//gl.glEnable(GL.GL_TEXTURE_2D);
	}
	
	private Vector3D getNorm(Vector3D A, Vector3D B)
	{
		Vector3D n=new Vector3D();
		n.setXYZ(A.y()*B.z()-A.z()*B.y(),
				A.z()*B.x()-A.x()*B.z(),
				A.x()*B.y()-A.y()*B.x());
		float l=n.magnitude();
		n.setXYZ(n.x()/l, n.y()/l, n.z()/l);
		return n;
	}
	
	private void loadShader(){
		 vert_shader = gl.glCreateShader(GL.GL_VERTEX_SHADER);
	        frag_shader = gl.glCreateShader(GL.GL_FRAGMENT_SHADER);
	        
	        BufferedReader brv = null;
			try {
				brv = new BufferedReader(
						new FileReader(
								"src/blin.vert"));
			} catch (FileNotFoundException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
	        String vsrc = "";
	        String line;
	        try {
				while ((line=brv.readLine()) != null) {
				  vsrc += line + "\n";
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        gl.glShaderSource(vert_shader, 1,
	        		new String[] {vsrc}, (int[])null, 0);
	        gl.glCompileShader(vert_shader);
	        
	        BufferedReader brf = null;
			try {
				brf = new BufferedReader(
						new FileReader(
								"src/blin.frag"));
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        String fsrc = "";
	        String lines;
	        try {
				while ((lines=brf.readLine()) != null) {
				  fsrc += lines + "\n";
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        gl.glShaderSource(frag_shader, 1,
	        		new String[] {fsrc}, (int[])null, 0);
	        gl.glCompileShader(frag_shader);
	        
	        shaderprogram = gl.glCreateProgram();
	        gl.glAttachShader(shaderprogram, vert_shader);
	        gl.glAttachShader(shaderprogram, frag_shader);
	        gl.glLinkProgram(shaderprogram);
	        gl.glValidateProgram(shaderprogram);
	 }
	
	private void arbWithMatrix(float x, float y){

		float time=System.currentTimeMillis()%100000 - start_time;

	    float pitch=5*(float)Math.sin((time/1800f*Math.PI + x*y))/180f*(float)Math.PI;
	    ///System.out.println(time);
		//float pitch=(time + x*y)/1000;
	    maty = Matrix4x4.set((float)Math.cos(pitch),0,(float)Math.sin(pitch),0,
                   0,1,0,0,
                   (float)-Math.sin(pitch),0,(float)Math.cos(pitch),0,
                   0,0,0,1);
    

	    matz = Matrix4x4.set((float)Math.cos(pitch),(float)-Math.sin(pitch),0,0,
    		(float)Math.sin(pitch),(float)Math.cos(pitch),0,0,
                   0,0,1,0,
                   0,0,0,1);
	    pitch=5*(float)Math.sin((time/900f*Math.PI + x*y))/180f*(float)Math.PI;
	    matx=Matrix4x4.set(1, 0, 0, 0,
	    		0, (float)Math.cos(pitch), (float)-Math.sin(pitch), 0,
	    		0, (float)Math.sin(pitch), (float)Math.cos(pitch),0,
	    		0, 0, 0, 1);
	    
	    shiftM=Matrix4x4.set(1, 0, 0, -x,
	    					 0, 1, 0, -y,
	    					 0, 0, 1, -3,
	    					 -x, -y, -3, 1);
	    backM=Matrix4x4.set(1, 0, 0, x,
				 			 0, 1, 0, y,
				 			 0, 0, 1, 3,
				 			 x, y, 3, 1);
	    maty=Matrix4x4.mult(matx,maty);
//	    maty=Matrix4x4.mult(matz,maty);
	}
}	